﻿#define _CRT_SECURE_NO_WARNINGS 

#include"snake.h"

//设置光标
void setpos(int x, int y)
{
	COORD pos = { x,y };

	HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(houtput, pos);
}

void welcome()
{
    setpos(40, 10);
    printf("欢迎来到贪吃蛇小游戏:");
    setpos(50, 25);
    system("pause");

    system("cls");
    setpos(40, 10);
    printf("←..→..↑..↓..来控制贪吃蛇的方向,f2..f1键分别控制减速和加速");
    setpos(50, 25);
    system("pause");
    system("cls");
}

void creatmap()
{
    setpos(0, 0);
    for (int i = 0; i <= 58; i += 2)
    {
        wprintf(L"%c", WALL);
    }
    setpos(0,26);
    for (int i = 0; i <= 58; i+=2)
    {
        wprintf(L"%c", WALL);
    }

    for (int i = 1; i < 26; i++)
    {
        setpos(0, i);
        wprintf(L"%c", WALL);
    }
    for (int i = 1; i < 26; i++)
    {
        setpos(58, i);
        wprintf(L"%c", WALL);
    }
}

void initsnake(psnake ps)
{
    psnakenode cur = NULL;
    
    for (int i = 0; i < 5; i++)
    {
        cur = (psnakenode)malloc(sizeof(snakenode));
        if (cur == NULL)
        {
            assert(cur);
        }
        cur->next = NULL;

        cur->x = 24 + 2 * i;
        cur->y = 5;

        if (ps->psnake == NULL)
        {
            ps->psnake = cur;
        }
        else
        {
            cur->next = ps->psnake;
            ps->psnake = cur;
        }
    }

    //打印蛇的身体
    cur = ps->psnake;
    while (cur)
    {
        setpos(cur->x, cur->y);
        wprintf(L"%c", BODY);
        cur = cur->next;
    }
    //初始化贪吃蛇的数据

    ps->score = 0;
    ps->sleeptime = 200;
    ps->foodweight = 10;
    ps->_dir = RIGHT;
    ps->_status = OK;

}

void creatfood(psnake ps)
{
    int x = 0;
    int y = 0;
again:
    do
    {
        x = rand() % 53 + 2;
        y = rand() % 25 + 1;
    } while (x % 2 != 0);
    psnakenode cur = ps->psnake;

    while (cur)
    {
        if (cur->x == x && cur->y == y)
        {
            goto again;
        }
        cur = cur->next;
    }

    psnakenode pfood = (psnakenode)malloc(sizeof(snakenode));
    if (pfood == NULL)
    {
        assert(pfood);
    }
    else
    {
        pfood->x = x;
        pfood->y = y;
        setpos(pfood->x, pfood->y);
        wprintf(L"%c", FOOD);
        ps->pfood = pfood;
    }
}

void gamehelp()
{
    setpos(64, 13);
    printf("不能穿墙，别咬到自己");
    setpos(64, 15);
    printf("用↑↓←→键控制贪吃蛇的方向\n");
    setpos(64, 17);
    printf("f1,f2分别对应加速和减速\n");
    setpos(64, 19);
    printf("esc退出游戏，空格键暂停游戏\n");

}

void gamestart(psnake ps)
{
	system("mode con cols=100 lines=30");
	system("title 贪吃蛇");

    //获取标准输出的句柄(用来标识不同设备的数值)
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);

    //影藏光标操作
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(hOutput, &CursorInfo);//获取控制台光标信息
    CursorInfo.bVisible = false; //隐藏控制台光标
    SetConsoleCursorInfo(hOutput, &CursorInfo);//设置控制台光标状态
    

    welcome();//打印游戏初始界面

    creatmap();//绘制地图

    initsnake(ps);//初始化蛇

    creatfood(ps);//第一个食物

    gamehelp();//游戏帮助

}

void pause()
{
    while (1)
    {
        if (KEY_PRESS(VK_SPACE))
        {
            break;
        }
        Sleep(300);
    }
}

//判断下一个是否是食物
int isfood(psnakenode psn, psnake ps)
{
    return ((psn->x == ps->pfood->x) && (psn->y == ps->pfood->y));
}

//是食物
void eatfood(psnakenode psn, psnake ps)
{
    psn->next = ps->psnake;
    ps->psnake = psn;
    psnakenode cur = ps->psnake;

    while (cur)
    {
        setpos(cur->x, cur->y);
        wprintf(L"%c", BODY);
        cur = cur->next;
    }

    ps->score += ps->foodweight;

    free(ps->pfood);
    creatfood(ps);
}

//不是食物


void nofood(psnakenode psn, psnake ps)
{
    //头插法
    psn->next = ps->psnake;
    ps->psnake = psn;
    psnakenode cur = ps->psnake;
    //打印蛇
    
    while (cur->next->next)
    {
        setpos(cur->x, cur->y);
        wprintf(L"%c", BODY);
        cur = cur->next;
    }

    //最后一个位置打印空格，然后释放节点
    setpos(cur->next->x, cur->next->y);
    printf("  ");
    free(cur->next);
    cur->next = NULL;
}


//判断死亡
int kill_by_wall(psnake ps)
{
    if (ps->psnake->x == 0 || ps->psnake->x == 56 || ps->psnake->y == 0 || ps->psnake->y == 26)
    {
        ps->_status = KILL_WALL;
        return 1;
    }
    return 0;
}

int kill_by_self(psnake ps)
{
    psnakenode cur = ps->psnake->next;
    while (cur)
    {
        if (ps->psnake->x == cur->x && ps->psnake->y == cur->y)
        {
            ps->_status = KILL_SELF;
            return 1;
        }
        cur = cur->next;
    }
    return 0;
}

void snakemove(psnake ps)
{
    psnakenode pnextnode = (psnakenode)malloc(sizeof(snakenode));
    if (pnextnode == NULL)
        assert(pnextnode);

    switch (ps->_dir)
    {
        case UP:
        {
            pnextnode->x = ps->psnake->x;
            pnextnode->y = ps->psnake->y - 1;
        }
        break;
        case DOWN:
        {
           pnextnode->x = ps->psnake->x;
            pnextnode->y = ps->psnake->y + 1;
        }
        break;
        case LEFT:
        {
            pnextnode->x = ps->psnake->x - 2;
            pnextnode->y = ps->psnake->y;
        }
        break;
        case RIGHT:
        {
            pnextnode->x = ps->psnake->x + 2;
            pnextnode->y = ps->psnake->y;
        }
        break;
    }

    if (isfood(pnextnode, ps))
    {
        eatfood(pnextnode, ps);
    }
    else
    {
        nofood(pnextnode, ps);
    }
 

    kill_by_wall(ps);
    kill_by_self(ps);
}

void gamerun(psnake ps)
{
    do {
        setpos(64, 10);
        printf("当前分数是%d  ", ps->score);
        printf("每个食物的分数是%d", ps->foodweight);

        if (KEY_PRESS(VK_UP) && ps->_dir != DOWN)
        {
            ps->_dir = UP;
        }
        else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP)
        {
            ps->_dir = DOWN;
        }
        else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT)
        {
            ps->_dir = LEFT;
        }
        else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT)
        {
            ps->_dir = RIGHT;
        }
        else if (KEY_PRESS(VK_SPACE))
        {
            pause();
        }
        else if (KEY_PRESS(VK_ESCAPE))
        {
            ps->_status = END;
            break;
        }
        else if (KEY_PRESS(VK_F1))
        {
            if (ps->sleeptime >= 50)
            {
                ps->sleeptime -= 30;
                ps->foodweight += 2;
            }
        }
        else if (KEY_PRESS(VK_F2))
        {
            if (ps->foodweight > 2)
            {
                ps->foodweight -= 2;
                ps->sleeptime += 30;
            }
        }
        Sleep(ps->sleeptime);
        snakemove(ps);
    } while (ps->_status == OK);
}


void gameend(psnake ps)
{
    psnakenode cur = ps->psnake;
    setpos(24, 12);
    switch (ps->_status)
    {
    case END:
        printf("您主动退出\n");
        break;
    case KILL_WALL:
        printf("撞到墙了\n");
        break;
    case KILL_SELF:
        printf("咬到自己了\n");
        break;
    }

    while (cur)
    {
        psnakenode del = cur;
        cur = cur->next;
        free(del);
    }
}